import Point from './Point';
import Scheduler from './Scheduler';
import Action from './Action';
import Event from '../event/Event';
import Listener from '../event/Listener';

export default class Node {
  constructor(canvas, style = {}) {
    this.canvas = canvas || null;                         // 画布
    this.position = style.position || 'absolute';           // 布局
    this.x = style.left || '0';                             // x坐标
    this.y = style.bottom || '0';                           // y坐标
    this.boxWidth = style.width || 0;                        // 宽度
    this.boxHeight = style.height;                        // 高度
    this.visible = style.visible !== undefined ? style.visible : true;                 // 是否显示
    this.rotation = style.rotation || 0;                  // 旋转角度
    this.scaleX = style.scaleX || 1;                      // X方向旋转
    this.scaleY = style.scaleY || 1;                      // Y方向
    this.alpha = style.alpha || 1;                        // 透明度
    this.color = style.color || '#000000';                // 颜色
    this.shadowOffsetX = style.shadowOffsetX || '';       // X方向阴影
    this.shadowOffsetY = style.shadowOffsetY || '';       // Y方向阴影
    this.shadowBlur = style.shadowBlur || '';             // 模糊程度
    this.shadowColor = style.shadowColor || '';           // 阴影颜色
    this.linearGradient = style.linearGradient || [];    // 渐变数组
    this.fontSize = style.fontSize || '20';               // 字体大小
    this.fontFamily = style.fontFamily || '微软雅黑';  // 字体
    this.fontColor = style.fontColor || style.color || '#000000'; // 字体颜色
    this.lineWidth = style.lineWidth || 3;                // 线宽
    this.textAlign = style.textAlign || 'left';
    this.paddingLeft = style.paddingLeft || '0';
    this.paddingRight = style.paddingRight || '0';
    this.paddingTop = style.paddingTop || 0;
    this.paddingBottom = style.paddingBottom || 0;
    this.lineDash = style.lineDash || [];
    this.border = style.border || '';
    this.borderTop = style.borderTop || '';
    this.borderRight = style.borderRight || '';
    this.borderBottom = style.borderBottom || '';
    this.borderLeft = style.borderLeft || '';
    this.childs = [];
    this.zIndex = style.zIndex || 1;                                      // z方向上层级关系
    this.parent = null;
    this.ext = style.ext || null;                                      // 节点关联数据
  }

  getRelativePixel(value, isHeight = false) {
    if (/calc\([^\)]+\)/.test(value)) {
      let numberReg = /calc\(([^\)]+)\)/.exec(value);
      let calcReg = numberReg[1].split(/\+|\-/);
      if (/\+/.test(numberReg[1])) {
        return Math.round(this.getRelativePixel(calcReg[0].trim(), isHeight)) + Math.round(this.getRelativePixel(calcReg[1].trim(), isHeight));
      } else {
        return Math.round(this.getRelativePixel(calcReg[0].trim(), isHeight)) - Math.round(this.getRelativePixel(calcReg[1].trim(), isHeight));
      }
    } else if (/\-?\d+%/.test(value)) {
      let numberReg = /(\-?\d+)%/.exec(value);
      if (this.parent) {
        // console.log('layer==>', this.parent)
        if (isHeight && this.parent.boxHeight) {
          return Math.round(this.parent.height * Number(numberReg[1]) / 100);
        } else if (this.parent.boxWidth) {
          return Math.round(this.parent.width * Number(numberReg[1]) / 100);
        }
      }
      return Math.round((isHeight ? this.canvas.height : this.canvas.width) * Number(numberReg[1]) / 100);
    } else if (/\-?\d+px/.test(value)) {
      let numberReg = /(\-?\d+)px/.exec(value);
      return Math.round(Number(numberReg[1]));
    } else if (/\-?\d+rem/.test(value)) {
      let numberReg = /(\-?\d+)rem/.exec(value);
      return Math.round(Number(this.canvas.fontSize) * Number(numberReg[1]));
    } else if (/\-?\d+em/.test(value)) {
      let numberReg = /(\-?\d+)em/.exec(value);
      if (this.parent) {
        return Math.round(Number(this.parent.fontSize) * Number(numberReg[1]));
      }
      return Math.round(Number(this.canvas.fontSize) * Number(numberReg[1]));
    }
    return Math.round(Number(value));
  }

  get left() {
    if (this.position === 'static') {
      if (this.parent) {
        let childs = this.parent.childs;
        let thisIndex = childs.findIndex(vo => vo === this);
        let sblingWidth = 0;
        for (let i = 0; i < thisIndex; i++) {
          if (childs[i].position !== 'absolute' && childs[i].position !== 'fixed') {
            sblingWidth += childs[i].width;
          }
        }
        return this.parent.left + sblingWidth + this.getRelativePixel(this.parent.paddingLeft);
      }
      return 0;
    } else if (this.position === 'relative') {
      if (this.parent) {
        let childs = this.parent.childs;
        let thisIndex = childs.findIndex(vo => vo === this);
        let sblingWidth = 0;
        for (let i = 0; i < thisIndex; i++) {
          if (childs[i].position !== 'absolute' && childs[i].position !== 'fixed') {
            sblingWidth += childs[i].width;
          }
        }
        return this.parent.left
          + sblingWidth
          + this.getRelativePixel(this.x)
          + this.getRelativePixel(this.parent.paddingLeft);
      }
    } else if (this.position === 'absolute') {
      if (this.parent) {
        return this.parent.left + this.getRelativePixel(this.x);
      }
    }
    return this.getRelativePixel(this.x);
  }

  get bottom() {
    if (this.position === 'static') {
      if (this.parent) {
        return this.parent.bottom + this.getRelativePixel(this.parent.paddingBottom, true);
      }
      return 0;
    } else if (this.position === 'relative') {
      if (this.parent) {
        return this.parent.bottom
          + this.getRelativePixel(this.parent.paddingBottom, true)
          + this.getRelativePixel(this.y, true);
      }
    } else if (this.position === 'absolute') {
      if (this.parent) {
        return this.parent.bottom
          + this.getRelativePixel(this.y, true);
      }
    }
    return this.getRelativePixel(this.y, true);
  }

  get width() {
    return this.getRelativePixel(this.boxWidth);
  }

  get height() {
    if (this.boxHeight) {
      if (/calc\([^\)]+\)/.test(this.boxHeight)) {
        let numberReg = /calc\(([^\)]+)\)/.exec(this.boxHeight);
        let calcReg = numberReg[1].split(/\+|\-/);
        if (/\+/.test(numberReg[1])) {
          return Math.round(this.getRelativePixel(calcReg[0].trim(), true)) + Math.round(this.getRelativePixel(calcReg[1].trim(), true));
        } else {
          return Math.round(this.getRelativePixel(calcReg[0].trim(), true)) - Math.round(this.getRelativePixel(calcReg[1].trim(), true));
        }
      } else if (/\d+%/.test(this.boxHeight)) {
        let numberReg = /(\d+)%/.exec(this.boxHeight);
        if (this.parent) {
          return Number(numberReg[1]) * this.parent.height / 100;
        }
        return Number(numberReg[1]) * this.canvas.height / 100;
      } else if (/\d+px/.test(this.boxHeight)) {
        let numberReg = /(\d+)px/.exec(this.boxHeight);
        return Number(numberReg[1]);
      } else if (/\d+rem/.test(this.boxHeight)) {
        let numberReg = /(\d+)rem/.exec(this.boxHeight);
        return Number(numberReg[1]) * this.canvas.fontSize;
      } else if (/\d+em/.test(this.boxHeight)) {
        let numberReg = /(\d+)em/.exec(this.boxHeight);
        if (this.parent) {
          return Number(numberReg[1]) * this.parent.fontSize;
        }
        return Number(numberReg[1]) * this.canvas.height;
      }
      return Number(this.boxHeight);
    } else {
      let childs = this.childs || [];
      let maxHeight = 0;
      for (let i = 0; i < childs.length; i++) {
        if (childs[i].height > maxHeight) {
          maxHeight = childs[i].height;
        }
      }
      return maxHeight;
    }
  }

  set left(value) {
    this.x = value;
  }

  set bottom(value) {
    this.y = value;
  }

  set width(value) {
    this.boxWidth = value;
  }

  set height(value) {
    this.boxHeight = value;
  }

  /**
   * 获取字体大小
   */
  get size() {
    if (this.fontSize) {
      return this.getRelativePixel(this.fontSize);
    }
    if (this.parent) {
      return this.parent.size;
    }
    return this.getRelativePixel(this.canvas.fontSize);
  }

  set padding(value) {
    const paddingArray = value.split(' ');
    if (paddingArray.length === 2) {
      this.paddingLeft = this.paddingRight = paddingArray[1];
      this.paddingTop = this.paddingBottom = paddingArray[0];
    } else if (paddingArray.length === 4) {
      this.paddingTop = paddingArray[0];
      this.paddingRight = paddingArray[1];
      this.paddingBottom = paddingArray[2];
      this.paddingLeft = paddingArray[3];
    }
  }

  set border(value) {
    this.borderTop = value;
    this.borderRight = value;
    this.borderBottom = value;
    this.borderLeft = value;
  }


  setAxis(_x, _y = 0) {
    if (_x instanceof Point) {
      this.x = _x.x;
      this.y = _x.y;
    } else {
      this.x = parseInt(_x);
      this.y = parseInt(_y);
    }
  }

  scheduleUpdate(dt) {
    this.updateScheduler = setInterval((dt) => {
      this.update(dt);
    }, dt);
  }

  unschedulerUpdate() {
    clearInterval(this.updateScheduler);
  }

  update(dt) {
    // 用于继承
  }

  schedule(callback, dt) {
    const scheduler = setInterval(callback(dt), dt);
    this.schedulers.push(new Scheduler(scheduler, callback));
  }

  runAction(action, callback) {
    if (action instanceof Action) {
      action.status = Action.STATUS.RUNNING;
      action.run(this, callback);
    } else {
      throw new Error('Error Arguments: action is not a instance of class Action');
    }
  }

  stopAction(action) {
    if (action instanceof Action) {
      action.stop();
    } else {
      throw new Error('Error Arguments: action is not a instance of class Action');
    }
  }

  unscheduler(callback) {
    for (const i in this.schedulers) {
      const scheduler = this.schedulers[i];
      if (scheduler.callback === callback) {
        this.schedulers.slice(i, 1);
        clearInterval(scheduler.scheduler);
        break;
      }
    }
  }

  containsPoint(point) {
    return false;
  }

  addEventListener(event, callback) {
    if (this.canvas === undefined || this.canvas === null) {
      throw new Error('No Canvas Found');
    }
    const ev = new Event(event, callback);
    const listener = new Listener(this, ev);
    this.canvas.eventManager.addEventListener(listener);
  }

  removeEventListener(event, callback) {
    if (this.canvas === undefined || this.canvas === null) {
      throw new Error('No Canvas Found');
    }
    const ev = new Event(event, callback);
    const listener = new Listener(this, ev);
    this.canvas.eventManager.removeEventListener(listener);
  }

  clearEventListener() {
    const listeners = this.canvas.eventManager.listeners.filter(item => item.obj === this);
    if (listeners) {
      for (const l of listeners) {
        this.canvas.eventManager.listeners.splice(this.canvas.eventManager.listeners.indexOf(l), 1);
      }
    }
  }

  draw(painter) {
    // Node 绘制函数
  }

  drawBorder(painter) {
    if (this.borderTop !== '') {
      painter.save();
      let borderValue = this.borderTop.split(' ');
      let borderType = borderValue[0] || 1;
      let borderWidth = borderValue[1] || '1';
      let borderColor = borderValue[2] || '#000000';
      painter.lineWidth = borderWidth = Number(borderWidth.replace('px', ''));
      if (borderType === 'dash') {
        painter.setLineDash([10, 3, 5]);
      }
      painter.strokeStyle = borderColor;
      painter.beginPath();
      painter.moveTo(this.left + borderWidth, this.canvas.height - (this.bottom + this.height - borderWidth));
      painter.lineTo(this.left + this.width - borderWidth, this.canvas.height - (this.bottom + this.height - borderWidth));
      painter.stroke();
      painter.restore();
    }
    if (this.borderRight !== '') {
      painter.save();
      let borderValue = this.borderRight.split(' ');
      let borderType = borderValue[0] || 1;
      let borderWidth = borderValue[1] || '1';
      let borderColor = borderValue[2] || '#000000';
      painter.lineWidth = borderWidth = Number(borderWidth.replace('px', ''));
      if (borderType === 'dash') {
        painter.setLineDash([10, 3, 5]);
      }
      painter.strokeStyle = borderColor;
      painter.beginPath();
      painter.moveTo(this.left + this.width - borderWidth, this.canvas.height - (this.bottom + this.height - borderWidth));
      painter.lineTo(this.left + this.width - borderWidth, this.canvas.height - this.bottom + borderWidth);
      painter.closePath();
      painter.stroke();
      painter.restore();
    }
    if (this.borderBottom !== '') {
      painter.save();
      let borderValue = this.borderBottom.split(' ');
      let borderType = borderValue[0] || 1;
      let borderWidth = borderValue[1] || '1';
      let borderColor = borderValue[2] || '#000000';
      painter.lineWidth = borderWidth = Number(borderWidth.replace('px', ''));
      if (borderType === 'dash') {
        painter.setLineDash([10, 3, 5]);
      }
      painter.strokeStyle = borderColor;
      painter.beginPath();
      painter.moveTo(this.left + borderWidth, this.canvas.height - this.bottom - borderWidth );
      painter.lineTo(this.left + this.width - borderWidth, this.canvas.height - this.bottom - borderWidth);
      painter.closePath();
      painter.stroke();
      painter.restore();
    }
    if (this.borderLeft !== '') {
      painter.save();
      let borderValue = this.borderLeft.split(' ');
      let borderType = borderValue[0] || 1;
      let borderWidth = borderValue[1] || '1';
      let borderColor = borderValue[2] || '#000000';
      painter.lineWidth = borderWidth = Number(borderWidth.replace('px', ''));
      if (borderType === 'dash') {
        painter.setLineDash([10, 3, 5]);
      }
      painter.strokeStyle = borderColor;
      painter.beginPath();
      painter.moveTo(this.left + borderWidth, this.canvas.height - (this.bottom + this.height - borderWidth));
      painter.lineTo(this.left + borderWidth, this.canvas.height - this.bottom + borderWidth);
      painter.closePath();
      painter.stroke();
      painter.restore();
    }
  }

  paint(config) {
    if (this.visible) {
      const { painter } = this.canvas;
      config.before && config.before(this, painter);
      this.drawBorder(painter);
      painter.save();
      painter.globalAlpha = this.alpha;
      painter.translate(this.left, this.canvas.height - this.bottom);
      painter.rotate(this.rotation * Math.PI / 180);
      painter.translate(-this.left, -this.bottom);
      painter.scale(this.scaleX, this.scaleY);
      painter.textAlign = this.textAlign;
      // 设置阴影
      if (!!this.shadowOffsetX) {
        painter.shadowOffsetX = this.shadowOffsetX;
      }
      if (!!this.shadowOffsetY) {
        painter.shadowOffsetY = this.shadowOffsetY;
      }
      if (!!this.shadowBlur) {
        painter.shadowBlur = this.shadowBlur;
      }
      if (!!this.shadowColor) {
        painter.shadowColor = this.shadowColor;
      }
      if (this.lineDash.length > 0) {
        painter.setLineDash(this.lineDash);
      }
      this.draw(painter);
      config.after && config.after(this, painter);
      painter.restore();
    }
  }
}
